package sim.core.utils;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.io.UnsupportedEncodingException;
import java.io.Writer;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import freemarker.core.ParseException;
import freemarker.template.Configuration;
import freemarker.template.MalformedTemplateNameException;
import freemarker.template.ObjectWrapper;
import freemarker.template.Template;
import freemarker.template.TemplateException;
import freemarker.template.TemplateExceptionHandler;
import freemarker.template.TemplateNotFoundException;

/**
 * 基于FreeMarker 2.3.25.jar模板操作工具类
 * 
 * @author 许芬勇
 * @date 2016-11-19 12:51
 * 
 */
@SuppressWarnings("deprecation")
public class FreeMarkerUtils {
	private static Configuration config = new Configuration(Configuration.VERSION_2_3_25);

	/**
	 * 
	 * 读取项目WebRoot下的模板文件
	 * 
	 * @param HttpServletRequest
	 * @param tempPath模板在WebRoot下的路径
	 * @param tempName模板名称
	 * @param dataModel模板数据
	 * @param writer流输出response形式
	 */
	public static void writer(HttpServletRequest request, String tempPath, Map<String, Object> data, Writer writer) {
		String[] result = FreeMarkerUtils.getTemp(tempPath);
		FreeMarkerUtils.setTempLoad(request, result[0]);
		FreeMarkerUtils.setTempData(result[1], data, writer);
		FreeMarkerUtils.closeQuietly(writer);
	}

	/**
	 * 读取项目包路径下的模板文件
	 * 
	 * @param tempPath模板所在src的包路径和模板名
	 * @description com/controller/temp/模板名
	 * @param dataModel写入模板的数据
	 * @param writer流输出response形式
	 */
	public static void writer(String tempPath, Map<String, Object> data, Writer writer) {
		String[] result = FreeMarkerUtils.getTemp(tempPath);
		FreeMarkerUtils.setTempLoad(result[0], null);
		FreeMarkerUtils.setTempData(result[1], data, writer);
		FreeMarkerUtils.closeQuietly(writer);
	}

	/**
	 * 读取指定路径的模板文件
	 * 
	 * @author Feny
	 * @date 2018年7月27日下午4:35:39
	 * @param tempPath
	 * @param data
	 * @param writer
	 */
	public static void writer(File tempPath, Map<String, Object> data, Writer writer) {
		FreeMarkerUtils.setTempLoad(tempPath.getParentFile(), null);
		FreeMarkerUtils.setTempData(tempPath.getName(), data, writer);
		FreeMarkerUtils.closeQuietly(writer);
	}

	/**
	 * 读取项目包路径下的模板文件
	 * 
	 * @param tempPath模板所在src的包路径和模板名
	 * @description /com/controller/temp/模板名
	 * @param dataModel写入模板的数据
	 * @param destFile生成文件的路径和文件名
	 * @description new File("E:/temp/newFileName.html");
	 */
	public static void writerToFile(String tempPath, Map<String, Object> data, File destFile) {
		String[] result = FreeMarkerUtils.getTemp(tempPath);
		FreeMarkerUtils.toFile(result[0], null, result[1], data, destFile);
	}

	/**
	 * 读取项目WebRoot下的模板文件
	 * 
	 * @param HttpServletRequest
	 * @param tempPath模板所在webRoot的类路径
	 * @description /temp/模板名
	 * @param dataModel写入模板的数据
	 * @param destFile生成文件的路径和文件名
	 * @description new File("E:/temp/newFileName.html");
	 */
	public static void writerToFile(HttpServletRequest request, String tempPath, Map<String, Object> data, File destFile) {
		String[] result = FreeMarkerUtils.getTemp(tempPath);
		FreeMarkerUtils.toFile(request, result[0], result[1], data, destFile);
	}

	/**
	 * 得到模板类路径和模板名称
	 * 
	 * @param tempPath
	 * @return 返回模板路径和模板名
	 */
	private static String[] getTemp(String tempPath) {
		String[] result = new String[2];
		if (!"".equals(tempPath)) {
			result[0] = tempPath.substring(0, tempPath.lastIndexOf("/"));
			result[1] = tempPath.substring(tempPath.lastIndexOf("/") + 1, tempPath.length());
		}
		return result;
	}

	/**
	 * 加载模板
	 * 
	 * @param tempPath加载模板路径
	 * @param tempName加载模板名称
	 */
	private static void setTempLoad(Object tempLoadType, String tempPath) {
		config.setTemplateExceptionHandler(TemplateExceptionHandler.RETHROW_HANDLER);
		config.setObjectWrapper(ObjectWrapper.BEANS_WRAPPER);
		config.setDefaultEncoding("UTF-8");
		config.setOutputEncoding("UTF-8");
		config.setLocale(Locale.CHINA);
		config.setDateFormat("yyyy-MM-dd");
		config.setTimeFormat("HH:mm:ss");
		config.setDateTimeFormat("yyyy-MM-dd HH:mm:ss");
		if (tempLoadType instanceof HttpServletRequest) {
			HttpServletRequest request = (HttpServletRequest) tempLoadType;
			config.setServletContextForTemplateLoading(request.getServletContext(), tempPath);
		} else if (tempLoadType instanceof File) {
			try {
				config.setDirectoryForTemplateLoading((File) tempLoadType);
			} catch (IOException e) {
				e.printStackTrace();
			}
		} else {
			config.setClassForTemplateLoading(Thread.currentThread().getContextClassLoader().getClass(), (String) tempLoadType);
		}
	}

	/**
	 * 生成模板
	 * 
	 * @param obj模板路径对象
	 * @param tempPath模板路径
	 * @param tempName模板名
	 * @param dataModel写入模板的数据
	 * @param destFile生成的文件的路劲和文件名
	 */
	private static void toFile(Object obj, String tempPath, String tempName, Map<String, Object> data, File destFile) {
		if (!destFile.isDirectory()) {
			new File(destFile.getParent()).mkdirs();
		}
		FreeMarkerUtils.setTempLoad(obj, tempPath);
		FileOutputStream outputStream = null;
		OutputStreamWriter writer = null;
		try {
			outputStream = new FileOutputStream(destFile);
			writer = new OutputStreamWriter(outputStream, "UTF-8");
			FreeMarkerUtils.setTempData(tempName, data, writer);
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (UnsupportedEncodingException e) {
			e.printStackTrace();
		} finally {
			FreeMarkerUtils.closeQuietly(writer);
			FreeMarkerUtils.closeQuietly(outputStream);
		}
	}

	/**
	 * 设置模板数据
	 * 
	 * @param tempName模板名称
	 * @param dataModel要填充的数据
	 * @param out输出流
	 */
	private static void setTempData(String tempName, Map<String, Object> dataModel, Writer writer) {
		try {
			Template template = config.getTemplate(tempName);
			template.process(dataModel, writer);
		} catch (TemplateNotFoundException e) {
			System.out.println("-----------该模板：" + tempName + "路径填写错误或不存在---------");
			e.printStackTrace();
		} catch (MalformedTemplateNameException e) {
			System.out.println("-----------畸形的模板---------");
			e.printStackTrace();
		} catch (ParseException e) {
			System.out.println("-----------数据解析错误---------");
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		} catch (TemplateException e) {
			System.out.println("---------模板数据填写错误----------" + e.getMessage());
		}
	}

	private static void closeQuietly(Writer writer) {
		try {
			if (writer != null) {
				writer.flush();
				writer.close();
			}
		} catch (IOException e) {
			System.out.println("IO流关闭异常" + e.getMessage());
		}
	}

	private static void closeQuietly(OutputStream out) {
		try {
			if (out != null) {
				out.flush();
				out.close();
			}
		} catch (IOException e) {
			System.out.println("IO流关闭异常" + e.getMessage());
		}
	}

	public static void main(String[] args) {
		Map<String, Object> data = new HashMap<>();
		data.put("msg", "test msg");
		File path = ClassPathUtils.getResourcePath("/public/test.ftl");
		FreeMarkerUtils.writer(path, data, new PrintWriter(System.out));
		// FreeMarkerUtils.writer("/public/test.ftl", data, new
		// PrintWriter(System.out));
	}
}
